package src

import (
	"github.com/sirupsen/logrus"
	"sync"
)

type IRoomManager interface {
	// Add 增加一个房间
	Add(r *Room)
	// Remove 删除一个房间
	Remove(r *Room)
	// All 获取所有房间
	All() []*Room
	// Has 检查是否已经有了某个房间
	Has(roomId string) bool
	// IntroduceClient 将客户端引入某个房间
	IntroduceClient(c *Client, r *Room)
	// KickOutClient 将客户端从某个房间中踢出去
	KickOutClient(c *Client, r *Room)
	// Push 推送消息
	Push(roomId string, message []byte)
	// Pick 获取一个房间
	Pick(roomId string) *Room
}

type RoomManager struct {
	// 房间列表
	rooms sync.Map
}

type IRoom interface {
	// Introduce 引入某个客户端
	Introduce(c *Client)
	// KickOut 踢出某个客户端
	KickOut(c *Client)
	// Has 检查当前房间内是否已经有了某个客户端
	Has(c *Client) bool
	// All 获取所有的客户端
	All() []*Client
}

// Room 房间类型
type Room struct {
	id      string
	clients sync.Map
}

var (
	onceRM sync.Once
	rm *RoomManager
)

func NewRoomManager() *RoomManager {
	onceRM.Do(func() {
		rm = &RoomManager{rooms: sync.Map{}}
	})
	return rm
}

func (rm *RoomManager) Add(r *Room) {
	logrus.WithFields(logrus.Fields{"location": "room manager", "method": "add"}).Info("Add room " + r.id)
	rm.rooms.Store(r.id, r)
}

func (rm *RoomManager) Remove(r *Room) {
	logrus.WithFields(logrus.Fields{"location": "room manager", "method": "remove"}).Info("Remove room " + r.id)
	if !rm.Has(r.id) {
		return
	}
	rm.rooms.Delete(r.id)
}

func (rm *RoomManager) All() []*Room {
	var rms []*Room
	rm.rooms.Range(func(key, value interface{}) bool {
		rms = append(rms, value.(*Room))
		return true
	})
	return rms
}

func (rm *RoomManager) Has(roomId string) bool {
	_, ok := rm.rooms.Load(roomId)
	return ok
}

func (rm *RoomManager) IntroduceClient(c *Client, r *Room) {
	logrus.WithFields(logrus.Fields{"location": "room manager", "method": "introduce client"}).Info("Introduce client " + c.id + " to room " + r.id)
	r.Introduce(c)
}

func (rm *RoomManager) KickOutClient(c *Client, r *Room) {
	logrus.WithFields(logrus.Fields{"location": "room manager", "method": "kick out client"}).Info("Kick out client " + c.id + " from room " + r.id)
	r.KickOut(c)
	if len(r.All()) == 0 {
		// 没有客户端了，这个房间也就没用了，直接删掉
		rm.Remove(r)
	}
}

func (rm *RoomManager) Push(roomId string, message []byte) {
	r, ok := rm.rooms.Load(roomId)
	if ok {
		clients := r.(*Room).All()
		for _, c := range clients {
			c.send <- message
		}
	}
}

func (rm *RoomManager) Pick(roomId string) *Room {
	r, ok := rm.rooms.Load(roomId)
	if !ok {
		return nil
	}
	return r.(*Room)
}

// NewRoom 房间区域
func NewRoom(id string) *Room {
	return &Room{
		id:      id,
		clients: sync.Map{},
	}
}

// Introduce 房间操作：包含某个客户端进来
func (r *Room) Introduce(c *Client) {
	logrus.WithFields(logrus.Fields{"location": "room", "method": "introduce"}).Info("Introduce client " + c.id)
	if r.Has(c) {
		return
	}
	r.clients.Store(c.id, c)
}

func (r *Room) KickOut(c *Client) {
	logrus.WithFields(logrus.Fields{"location": "room", "method": "kick out"}).Info("Kick out client " + c.id)
	if !r.Has(c) {
		return
	}
	r.clients.Delete(c.id)
}

func (r *Room) Has(c *Client) bool {
	_, ok := r.clients.Load(c.id)
	return ok
}

func (r *Room) All() []*Client {
	var clts []*Client
	r.clients.Range(func(key, value interface{}) bool {
		clts = append(clts, value.(*Client))
		return true
	})
	return clts
}
